-- Copyright (c) 2010, Pavel Kovar
-- All rights reserved.
--
---------------------------------------------------------------------------------------
-- This file is a part of the Witch Navigator project

-- nco_code
-- Implemented
--   * 6x numerical controlled oscillators for code generation
--   * 6x memory based PRN generators
--   * PRN memory for six codes
--
-- Consecutive processing in single HW 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity nco_code is
	generic (
			  prn_length : integer := 10230
			  );

    Port ( b_code : in  STD_LOGIC_VECTOR (31 downto 0);
           phase : in  STD_LOGIC_VECTOR (2 downto 0);
           clk_dsp : in  STD_LOGIC;
           cor_space : in  STD_LOGIC_VECTOR (2 downto 0);
           prn_e : out  STD_LOGIC;
           prn_l : out  STD_LOGIC;
           prn_tic_e : out STD_LOGIC;
           prn_tic_l : out STD_LOGIC;
           nco_code_out : out STD_LOGIC_VECTOR (31 downto 0);
              -- PRN mem interface
           clk_ctr : in STD_LOGIC;	  
           mem_we : in STD_LOGIC_vector(3 downto 0);
           mem_addr : in STD_LOGIC_VECTOR(11 downto 0);
           mem_in : in STD_LOGIC_VECTOR(31 downto 0));
end nco_code;

architecture Behavioral of nco_code is

signal accreg0, accreg2, accreg3, accreg4, accreg5: std_logic_vector(39 downto 0) := "0000000000000000000000000000000000000000"; 
signal prn_tic0, prn_tic3, prn_tic4, prn_tic5: std_logic;
signal prn_overflow3: std_logic;
signal mprn_out : std_logic_vector(7 downto 0);
signal prn_del : std_logic_vector(48 downto 0); 
signal tic_del : std_logic_vector(48 downto 0);
signal mprn_out_r : std_logic_vector(7 downto 0);

signal prn_tic_blockD1, prn_tic_blockD2, prn_tic_blockD3, prn_tic_blockD4, prn_tic_blockD5, prn_tic_blockD6 : std_logic;

component prn_mem
	port (
	clka: IN std_logic;
	wea: IN std_logic_VECTOR(3 downto 0);
	addra: IN std_logic_VECTOR(11 downto 0);
	dina: IN std_logic_VECTOR(31 downto 0);
	clkb: IN std_logic;
	addrb: IN std_logic_VECTOR(13 downto 0);
	doutb: OUT std_logic_VECTOR(7 downto 0));
end component;

component caccu
	port (
	a: IN std_logic_VECTOR(31 downto 0);
	b: IN std_logic_VECTOR(39 downto 0);
	clk: IN std_logic;
	s: OUT std_logic_VECTOR(39 downto 0));
end component;


begin

-- For Galileo E1 
GALILEO_E1: IF prn_length = 4092*2 GENERATE
begin	
	process (clk_dsp)
	begin
		if clk_dsp'event and clk_dsp = '1' then
			prn_tic_blockD2 <= prn_tic_blockD1;
			prn_tic_blockD3 <= prn_tic_blockD2;
			prn_tic_blockD4 <= prn_tic_blockD3;
			prn_tic_blockD5 <= prn_tic_blockD4;
			prn_tic_blockD6 <= prn_tic_blockD5;

						
			if accreg2(39 downto 26) = CONV_STD_LOGIC_VECTOR(	prn_length/4, 14) or 
				accreg2(39 downto 26) = CONV_STD_LOGIC_VECTOR(2*prn_length/4, 14) or
				accreg2(39 downto 26) = CONV_STD_LOGIC_VECTOR(3*prn_length/4, 14) or
				accreg2(39 downto 26) = CONV_STD_LOGIC_VECTOR(4*prn_length/4, 14) then
				-- prn_tic3 has to be generated only onec in PRN chip
				if prn_tic_blockD6 = '0' then
					prn_tic3 <='1';
					prn_tic_blockD1 <= '1';
				else
					prn_tic3 <='0';
					prn_tic_blockD1 <= '1';
				end if;
			else
				prn_tic3 <='0';
				prn_tic_blockD1 <='0';
			end if;
			if accreg2(39 downto 26) = CONV_STD_LOGIC_VECTOR(4*prn_length/4, 14) then
				prn_overflow3 <='1';
			else
				prn_overflow3 <='0';
			end if;
		end if;
	end process;	
END GENERATE GALILEO_E1;

OTHER_SIG: IF prn_length /= 4092*2 GENERATE
begin	
	process (clk_dsp)
	begin
		if clk_dsp'event and clk_dsp = '1' then
			if accreg2(39 downto 26) = CONV_STD_LOGIC_VECTOR(prn_length, 14)  then
				prn_tic3 <='1';
				prn_overflow3 <='1';
			else
				prn_tic3 <='0';
				prn_overflow3 <='0';				
			end if;
		end if;
	end process;	
END GENERATE OTHER_SIG;

process (clk_dsp)
begin
	if clk_dsp'event and clk_dsp = '1' then
		mprn_out_r <= mprn_out;
		accreg3 <= accreg2;
		accreg4(25 downto 0) <= accreg3(25 downto 0); 
		accreg5 <= accreg4;
		accreg0 <= accreg5; 


      if prn_overflow3 ='1' then
			accreg4(39 downto 26) <= "00000000000000";
		else
			accreg4(39 downto 26) <= accreg3(39 downto 26);
      end if;		
		prn_tic4 <= prn_tic3;
		prn_tic5 <= prn_tic4;
		prn_tic0 <= prn_tic5;		
		-- prn delay 
		prn_del(48 downto 1) <= prn_del(47 downto 0);
		-- tic delay
		tic_del(48 downto 1) <= tic_del(47 downto 0);
	end if;
end process;

-- PRN code selection
prn_del(0) <= mprn_out_r(0) when phase = "000" else 
              mprn_out_r(1) when phase = "001" else
              mprn_out_r(2) when phase = "010" else
              mprn_out_r(3) when phase = "011" else
              mprn_out_r(4) when phase = "100" else
              mprn_out_r(5) when phase = "101" else
              mprn_out_r(6) when phase = "110" else
              mprn_out_r(7) when phase = "111" else
              mprn_out_r(7);
			
nco_code_out <= accreg0(39 downto 8);
prn_tic_e <= prn_tic0;
tic_del(0) <= prn_tic0;
prn_e <= prn_del(0);


-- late branch delay control 
prn_l <= prn_del(6) when cor_space = "000" else
			prn_del(12) when cor_space = "001" else
			prn_del(18) when cor_space = "010" else
			prn_del(24) when cor_space = "011" else
			prn_del(30) when cor_space = "100" else
			prn_del(36) when cor_space = "101" else
			prn_del(42) when cor_space = "110" else
			prn_del(48) when cor_space = "111" else
			prn_del(48);
			
prn_tic_l <= tic_del(6)  when cor_space = "000" else
				 tic_del(12) when cor_space = "001" else
			    tic_del(18) when cor_space = "010" else
			    tic_del(24) when cor_space = "011" else
			    tic_del(30) when cor_space = "100" else
			    tic_del(36) when cor_space = "101" else
			    tic_del(42) when cor_space = "110" else
			    tic_del(48) when cor_space = "111" else
			    tic_del(48);			
			
-- latence 2
cacc : caccu
		port map (
			a => b_code,
			b => accreg0,
			clk => clk_dsp,
			s => accreg2);
-- latence 1
prnm : prn_mem
		port map (
			clka => clk_ctr,
			wea => mem_we,
			addra => mem_addr,
			dina => mem_in,
			clkb => clk_dsp,
			addrb => accreg4(39 downto 26),
			doutb => mprn_out);

end Behavioral;

